home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
cit.arc
/
MSG.C
< prev
next >
Wrap
C/C++ Source or Header
|
1986-01-12
|
47KB
|
1,552 lines
/************************************************************************/
/* msg.c */
/* */
/* Message handling for Citadel bulletin board system */
/************************************************************************/
/************************************************************************/
/* history */
/* */
/* 86Jan12 HAW deleteMessage and moveMessage split from pullIt. */
/* 86Jan04 HAW Null-named rooms no longer mess up Aide room/msg del. */
/* 85Nov11 HAW Rewrite yesterday's mistake. */
/* 85Nov10 HAW Fix Held net messages, problem with reverse deletions. */
/* 85Sep21 HAW Fix bugs of 85Sep15. */
/* 85Sep15 HAW Update for adding tag indicating a message is outgoing. */
/* 85Aug27 HAW Move putNetMessage into this file from MISC.C. */
/* 85Aug24 HAW Install code for having two msg disks, 1 RAM, 1 disk. */
/* 85Aug20 HAW Install code for System Announcement. */
/* 85Aug17 HAW Update to onLine() and gotCarrier(). */
/* 85Aug08 HAW Fix mAbort() to detect 'silent' carrier loss. */
/* 85Jul05 HAW Cull out ^Ls from messages. */
/* 85Jul04 HAW Insert code to handle "moving" messages. */
/* 85Jun03 HAW Tweak code for networking stuff */
/* 85May16 HAW Install <H>eld message option */
/* 85May13 HAW Now last message read by caller is printed on <N>ew */
/* 85Mar20 HAW Time stamp messages for the nosy types. */
/* 85Mar13 HAW Move zapMsgFile() to confg.c */
/* 85Mar10 HAW Stop printing messages when lose carrier. */
/* 85Mar06 HAW Change mPrintf() to use mFormat(). */
/* 85Feb22 HAW Implement upload/download. */
/* 85Feb20 HAW Implement IMPERVIOUS flag. */
/* 85Jan19 HAW Move findPerson() from here to LOG.C. */
/* 84Sep19 HAW Can NOT send mail to oneself. */
/* 84Sep16 JLS Now recipient's name is recorded like Citadel thinks. */
/* 84Sep15 HAW Modified for "POLICY.HLP" masses file. */
/* 84Sep01 HAW Msg # no longer split. Note networking problem. */
/* 84Aug30 HAW Start upgrade to MS-DOS. */
/* 84Jul03 HAW mPrintf, dPrintf, and mWCprintf upgraded to BDS 1.50a. */
/* 84Jun23 HAW & JLS Unused local variables zapped. */
/* 84Jun07 HAW Responses in Mail now automatically get recipient. */
/* 84May07 JLS & HAW Implemented the configuration switch ENTEROK. */
/* 84Mar29 HAW Start upgrade to BDS C 1.50a, identify _spr problem. */
/* 83Mar03 CrT & SB Various bug fixes... */
/* 83Feb27 CrT Save private mail for sender as well as recipient. */
/* 83Feb23 Various. transmitFile() won't drop first char on WC... */
/* 82Dec06 CrT 2.00 release. */
/* 82Nov05 CrT Stream retrieval. Handles messages longer than MAXTEXT.*/
/* 82Nov04 CrT Revised disk format implemented. */
/* 82Nov03 CrT Individual history begun. General cleanup. */
/************************************************************************/
#include "ctdl.h"
#define TEST_SYS
/************************************************************************/
/* contents */
/* */
/* aideMessage() saves auto message in Aide> */
/* dGetWord() reads a word off disk */
/* doActualWrite() to allow two message files for bkp */
/* doFlush() writes out to specified msg file */
/* # dPree() special utility for dPrintf & mWCprintf */
/* # dPrintf() printf() that writes to disk */
/* fakeFullCase() converts uppercase message to mixed case*/
/* flushMsgBuf() wraps up message-to-disk store */
/* getMessage() load message into RAM */
/* getMsgChar() returns successive chars off disk */
/* getMsgStr() reads a string out of message.buf */
/* getWord() gets one word from message buffer */
/* mAbort() checks for user abort of typeout */
/* makeMessage() menu-level message-entry routine */
/* mFormat() formats a string to modem and console */
/* mPeek() sysop debugging tool--shows ctdlmsg.sys */
/* # mPrintf() writes a line to modem & console */
/* # mWCprintf() special mPrintf for WC transfers */
/* noteLogMessage() enter message into log record */
/* noteMessage() enter message into current room */
/* note2Message() noteMessage() local */
/* printMessage() prints a message on modem & console */
/* pullIt() sysop special message-removal routine */
/* putLong() puts a long integer to file */
/* putMessage() write message to disk */
/* putMsgChar() writes successive message chars to disk */
/* putNetMessage() write net message to disk */
/* putWord() writes one word to modem & console */
/* showMessages() menu-level show-roomful-of-messages fn */
/* startAt() setup to read a message off disk */
/* unGetMsgChar() return a char to getMsgChar() */
/* */
/* # -- functions that will give problems when porting */
/************************************************************************/
/************************************************************************/
/* External variable declarations in MSG.C */
/************************************************************************/
static unsigned char GMCCache; /* To unGetMsgChar() into */
struct msgB msgBuf; /* The -sole- message buffer */
struct msgB tempMess; /* For held messages */
FILE *msgfl; /* file descriptor for the msg file */
FILE *msgfl2; /* disk based backup msg file */
unsigned char crtColumn; /* current position on screen */
char outFlag = OUTOK; /* will be one of the above */
char pullMessage = FALSE;/* true to pull current message*/
unsigned pulledMLoc;/* loc of pulled message */
ulong pulledMId = 0l; /* id of message to be pulled */
char heldMessage;
label oldTarget;
#ifdef _C86_BIG /*Black magic stuff */
static int j;
static unsigned char **starr[5];
#endif
struct mBuf {
unsigned char sectBuf[SECTSIZE];
int thisChar;
unsigned thisSector;
int oldChar;
unsigned oldSector;
} ;
static struct mBuf mFile1, mFile2;
/************************************************************************/
/* External variable definitions for MSG.C */
/************************************************************************/
extern struct config cfg; /* Configuration variables */
extern struct lTable *logTab; /* The people */
extern struct logBuffer logBuf; /* Buffer for the pippuls */
extern struct aRoom roomBuf; /* Room buffer */
extern struct rTable roomTab[MAXROOMS];
extern struct netTable *netTab;
extern struct netBuffer netBuf;
extern int thisRoom; /* Current room */
extern int thisNet; /* Current node in use */
extern int thisLog; /* Current log position */
extern char echo; /* Output flag */
extern char echoChar;
extern char loggedIn; /* Logged in flag */
extern char aide; /* aide? */
extern char sendTime; /* User wants to know time */
extern char whichIO; /* Who gets output? */
extern unsigned char termWidth; /* How big's the terminal? */
extern char prevChar; /* Output's evil purposes */
extern char expert; /* Expert? */
extern char usingWCprotocol;/* Flag */
extern char haveCarrier; /* Flag */
extern char onConsole; /* Flag */
extern char oldToo; /* Print old msg on New request?*/
extern int exitValue;
extern char debug;
/************************************************************************/
/* External function definitions for MSG.C */
/************************************************************************/
char BBSCharReady();
char iChar();
char toUpper();
char putMessage();
unsigned char getMsgChar();
/************************************************************************/
/* aideMessage() saves auto message in Aide> */
/************************************************************************/
aideMessage(noteDeletedMessage)
char noteDeletedMessage;
{
int ourRoom;
/* message is already set up in msgBuf.mbtext */
putRoom(ourRoom = thisRoom);
getRoom(AIDEROOM);
strCpy(msgBuf.mbauth, "Citadel");
msgBuf.mbto[0] = '\0';
if (putMessage( /* uploading== */ FALSE)) noteMessage(NULL, ERROR);
if (noteDeletedMessage) {
note2Message(pulledMId, pulledMLoc);
}
putRoom(AIDEROOM);
noteRoom();
getRoom(ourRoom);
}
/************************************************************************/
/* deleteMessage() deletes message for pullIt() */
/************************************************************************/
deleteMessage(m)
int m;
{
int i;
/* record vital statistics for possible insertion elsewhere: */
mPrintf("elete message\n ");
pulledMLoc = roomBuf.msg[m].rbmsgLoc;
pulledMId = roomBuf.msg[m].rbmsgNo ;
if (thisRoom == AIDEROOM) return TRUE;
/* return emptied slot: */
for (i = m; i > 0; i--) {
roomBuf.msg[i].rbmsgLoc = roomBuf.msg[i - 1].rbmsgLoc;
roomBuf.msg[i].rbmsgNo = roomBuf.msg[i - 1].rbmsgNo ;
}
roomBuf.msg[0].rbmsgNo = 0l; /* mark new slot at end as free */
roomBuf.msg[0].rbmsgLoc = 0; /* mark new slot at end as free */
/* store revised room to disk before we forget... */
noteRoom();
putRoom(thisRoom);
/* note in Aide>: */
sPrintf(msgBuf.mbtext, "Following message from %s deleted by %s:",
(msgBuf.mbauth[0]) ? msgBuf.mbauth : "<anonymous>", logBuf.lbname);
aideMessage( /* noteDeletedMessage== */ TRUE);
return TRUE;
}
/************************************************************************/
/* dGetWord() fetches one word from current message, off disk */
/* returns TRUE if more words follow, else FALSE */
/************************************************************************/
char dGetWord(dest, lim)
char *dest;
int lim;
{
char c;
--lim; /* play it safe */
/* pick up any leading blanks: */
for (c = getMsgChar(); c == ' ' && c && lim; c = getMsgChar()) {
if (lim) { *dest++ = c; lim--; }
}
/* step through word: */
for ( ; c != ' ' && c && lim; c = getMsgChar()) {
if (lim) { *dest++ = c; lim--; }
}
/* trailing blanks: */
for ( ; c == ' ' && c && lim; c = getMsgChar()) {
if (lim) { *dest++ = c; lim--; }
}
if (c) unGetMsgChar(c); /* took one too many */
*dest = '\0'; /* tie off string */
return c;
}
/************************************************************************/
/* doActualWrite() to allow automatic bkp of msg file from RAM. */
/************************************************************************/
doActualWrite(whichmsg, mFile, c)
FILE *whichmsg;
struct mBuf *mFile;
unsigned c;
{
ulong temp;
int toReturn = 0;
if (mFile->sectBuf[mFile->thisChar] == 0xFF) {
/* obliterating a msg */
toReturn = 1;
}
mFile->sectBuf[mFile->thisChar] = c;
mFile->thisChar = ++mFile->thisChar % SECTSIZE;
if (mFile->thisChar == 0) { /* time to write sector out and get next: */
temp = mFile->thisSector;
temp *= SECTSIZE;
fseek(whichmsg, temp, 0);
crypte(mFile->sectBuf, SECTSIZE, 0);
if (fwrite(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
exitValue = CRASH_EXIT;
crashout("?putMsgChar-write fail");
}
mFile->thisSector = ++mFile->thisSector % cfg.maxMSector;
temp = mFile->thisSector;
temp *= SECTSIZE;
fseek(whichmsg, temp, 0);
if (fread(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
exitValue = CRASH_EXIT;
crashout("?putMsgChar-read fail");
}
crypte(mFile->sectBuf, SECTSIZE, 0);
}
return toReturn;
}
/************************************************************************/
/* doFlush() do actual writeup for specified msg file */
/************************************************************************/
doFlush(whichmsg, mFile)
FILE *whichmsg;
struct mBuf *mFile;
{
long int s;
s = mFile->thisSector;
s *= SECTSIZE;
fseek(whichmsg, s, 0);
crypte(mFile->sectBuf, SECTSIZE, 0);
if (fwrite(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
exitValue = CRASH_EXIT;
crashout("?ctdlmsg.sys write fail");
}
crypte(mFile->sectBuf, SECTSIZE, 0);
}
/************************************************************************/
/* dPree() Special utility for dPrintf() and mWCprintf */
/************************************************************************/
dPree(func, start, length)
int func;
char *start;
unsigned length;
{
int (*fn)(), putMsgChar(), sendWCChar();
switch (func) {
case 0: fn = &putMsgChar; break;
case 1: fn = &sendWCChar; break;
default: exitValue = CRASH_EXIT; crashout("dPree error value!");
}
while (length--)
if ((*fn)(*start++) == ERROR) return ERROR;
}
/************************************************************************/
/* dPrintf() write from format+args to disk */
/************************************************************************/
dPrintf(format, args)
unsigned args;
unsigned char *format;
{
int dPree();
_fmtout(&dPree, 0, format, &args);
}
/************************************************************************/
/* fakeFullCase() converts a message in uppercase-only to a */
/* reasonable mix. It can't possibly make matters worse... */
/* Algorithm: First alphabetic after a period is uppercase, all */
/* others are lowercase, excepting pronoun "I" is a special case. */
/* We assume an imaginary period preceding the text. */
/************************************************************************/
fakeFullCase(text)
char *text;
{
char toLower(), toUpper();
char *c;
char lastWasPeriod;
char state;
for(lastWasPeriod=TRUE, c=text; *c; c++) {
if (
*c != '.'
&&
*c != '?'
&&
*c != '!'
) {
if (isAlpha(*c)) {
if (lastWasPeriod) *c = toUpper(*c);
else *c = toLower(*c);
lastWasPeriod = FALSE;
}
} else {
lastWasPeriod = TRUE ;
}
}
/* little state machine to search for ' i ': */
#define NUTHIN 0
#define FIRSTBLANK 1
#define BLANKI 2
for (state=NUTHIN, c=text; *c; c++) {
switch (state) {
case NUTHIN:
if (isSpace(*c)) state = FIRSTBLANK;
else state = NUTHIN ;
break;
case FIRSTBLANK:
if (*c == 'i') state = BLANKI ;
else state = NUTHIN ;
break;
case BLANKI:
if (isSpace(*c)) state = FIRSTBLANK;
else state = NUTHIN ;
if (!isAlpha(*c)) *(c-1) = 'I';
break;
}
}
}
/************************************************************************/
/* flushMsgBuf() wraps up writing a message to disk, takes into */
/* account 2nd msg file if necessary */
/************************************************************************/
flushMsgBuf()
{
doFlush(msgfl, &mFile1);
if (cfg.mirror)
doFlush(msgfl2, &mFile2);
}
/************************************************************************/
/* getMessage() reads a message off disk into RAM. */
/* a previous call to setUp has specified the message. */
/************************************************************************/
getMessage()
{
unsigned char c;
/* clear msgBuf out */
msgBuf.mbauth[ 0] = '\0';
msgBuf.mbtime[ 0] = '\0';
msgBuf.mbdate[ 0] = '\0';
msgBuf.mborig[ 0] = '\0';
msgBuf.mboname[0] = '\0';
msgBuf.mbroom[ 0] = '\0';
msgBuf.mbsrcId[0] = '\0';
msgBuf.mbtext[ 0] = '\0';
msgBuf.mbaddr[ 0] = '\0';
msgBuf.mbto[ 0] = '\0';
do c = getMsgChar(); while (c != 0xFF); /* find start of msg */
msgBuf.mbheadChar = mFile1.oldChar; /* record location */
msgBuf.mbheadSector = mFile1.oldSector;
getMsgStr(msgBuf.mbId, NAMESIZE);
do {
c = getMsgChar();
switch (c) {
case 'A': getMsgStr(msgBuf.mbauth, NAMESIZE); break;
case 'D': getMsgStr(msgBuf.mbdate, NAMESIZE); break;
case 'C': getMsgStr(msgBuf.mbtime, NAMESIZE); break;
case 'M': /* just exit -- we'll read off disk */ break;
case 'N': getMsgStr(msgBuf.mboname, NAMESIZE); break;
case 'O': getMsgStr(msgBuf.mborig, NAMESIZE); break;
case 'R': getMsgStr(msgBuf.mbroom, NAMESIZE); break;
case 'S': getMsgStr(msgBuf.mbsrcId, NAMESIZE); break;
case 'T': getMsgStr(msgBuf.mbto, NAMESIZE); break;
case 'Q': getMsgStr(msgBuf.mbaddr, NAMESIZE); break;
default:
getMsgStr(msgBuf.mbtext, MAXTEXT); /* discard unknown field */
msgBuf.mbtext[0] = '\0';
break;
}
} while (c != 'M' && isAlpha(c));
}
/************************************************************************/
/* getMsgChar() returns sequential chars from message on disk */
/************************************************************************/
unsigned char getMsgChar()
{
#ifdef NEED_VISIBLE
char visible();
#endif
long work;
char toReturn;
if (GMCCache) { /* someone did an unGetMsgChar() --return it */
toReturn= GMCCache;
GMCCache= '\0';
return toReturn;
}
mFile1.oldChar = mFile1.thisChar;
mFile1.oldSector = mFile1.thisSector;
toReturn = mFile1.sectBuf[mFile1.thisChar];
mFile1.thisChar = ++mFile1.thisChar % SECTSIZE;
if (mFile1.thisChar == 0) {
/* time to read next sector in: */
mFile1.thisSector = ++mFile1.thisSector % cfg.maxMSector;
work = mFile1.thisSector;
work *= SECTSIZE;
fseek(msgfl, work, 0);
if (fread(mFile1.sectBuf, SECTSIZE, 1, msgfl) != 1) {
exitValue = CRASH_EXIT;
crashout("?nextMsgChar-read fail");
}
crypte(mFile1.sectBuf, SECTSIZE, 0);
}
return(toReturn);
}
/************************************************************************/
/* getMsgStr() reads a string from message.buf */
/************************************************************************/
getMsgStr(dest, lim)
char *dest;
int lim;
{
char c;
while (c = getMsgChar()) { /* read the complete string */
if (lim) { /* if we have room then */
lim--;
*dest++ = c; /* copy char to buffer */
}
}
*dest = '\0'; /* tie string off with null */
}
/************************************************************************/
/* getWord() fetches one word from current message */
/************************************************************************/
int getWord(dest, source, offset, lim)
char *dest, *source;
int lim, offset;
{
int i, j;
/* skip leading blanks if any */
for (i = 0; source[offset+i] ==' ' && i < lim; i++);
/* step over word */
for (;
source[offset+i] != ' ' &&
i < lim &&
source[offset+i] != 0;
i++
);
/* pick up any trailing blanks */
for (; source[offset+i]==' ' && i<lim; i++);
/* copy word over */
for (j = 0; j < i; j++) dest[j] = source[offset+j];
dest[j] = 0; /* null to tie off string */
return(offset+i);
}
/************************************************************************/
/* mAbort() returns TRUE if the user has aborted typeout */
/* Globals modified: outFlag */
/************************************************************************/
char mAbort()
{
char c, toReturn, oldEcho;
/* Check for abort/pause from user */
if (outFlag == IMPERVIOUS)
toReturn = FALSE;
else if (!BBSCharReady()) {
if (haveCarrier && !gotCarrier())
modIn(); /* Let modIn() report the problem */
toReturn = FALSE;
} else {
oldEcho = echo;
echo = NEITHER;
echoChar = 0;
c = toUpper(iChar());
switch (c) {
case XOFF:
case 'P': /* pause: */
c = iChar(); /* wait to resume */
if (
toLower(c) == 'd'
&&
aide
) pullMessage = TRUE;
toReturn = FALSE;
break;
case 'J': /* jump paragraph:*/
outFlag = OUTPARAGRAPH;
toReturn = FALSE;
break;
case 'N': /* next: */
outFlag = OUTNEXT;
toReturn = TRUE;
break;
case 'S': /* skip: */
outFlag = OUTSKIP;
toReturn = TRUE;
break;
default:
toReturn = FALSE;
break;
}
echo = oldEcho;
}
return toReturn;
}
/************************************************************************/
/* makeMessage is menu-level routine to enter a message */
/* Return: TRUE if message saved else FALSE */
/************************************************************************/
makeMessage(uploading, name_Auth, mode, netMess)
char *name_Auth; /* name of recipient unless name_Auth == 0 */
char uploading; /* TRUE if message is coming via WC protocol */
char mode; /* Is message being continued? */
char netMess;
{
char allUpper, *pc, toReturn;
struct logBuffer lBuf;
int logNo;
toReturn = FALSE;
if (mode) {
if (!heldMessage) {
mPrintf(" \n No message in the Held buffer!\007\n ");
return FALSE;
}
heldMessage = FALSE;
strTran(msgBuf.mbtext, tempMess.mbtext);
if (thisRoom == MAILROOM)
strTran(msgBuf.mbto, tempMess.mbto);
strTran(msgBuf.mbaddr, tempMess.mbaddr);
}
else {
msgBuf.mbto[0] = 0;
}
logNo = ERROR;/* not needed, but it's nice to initialize... */
if (thisRoom != MAILROOM && !loggedIn && !cfg.unlogEnterOk) {
mPrintf("Must log in to enter messages except MAIL to the SYSOP\n ");
return FALSE;
}
if (thisRoom != MAILROOM) msgBuf.mbto[0] = FALSE;
else {
if (!loggedIn || (!aide && cfg.noMail)) {
strCpy(msgBuf.mbto, "Sysop");
mPrintf(" (private mail to 'sysop')\n ");
} else {
if (name_Auth == NULL && msgBuf.mbto[0] == 0) {
getNormStr("recipient", msgBuf.mbto, NAMESIZE, ECHO);
if (strLen(msgBuf.mbto) == 0) return FALSE;
}
else if (name_Auth != NULL)
strCpy(msgBuf.mbto, name_Auth);
if (!netMess && !msgBuf.mbaddr[0]) {
logNo = findPerson(msgBuf.mbto, &lBuf);
if ((logNo == ERROR &&
(strCmpU(msgBuf.mbto, "Citadel") != SAMESTRING ||
!aide || !onConsole) &&
hash(msgBuf.mbto) != hash("Sysop")) ||
strlen(msgBuf.mbto) == 0) {
mPrintf("No '%s' known", msgBuf.mbto);
return FALSE;
}
if (hash(msgBuf.mbto) != hash("Sysop") &&
strCmpU(msgBuf.mbto, "Citadel") != SAMESTRING)
strCpy(msgBuf.mbto, lBuf.lbname); /* Get "true" rep. */
if (strCmp(msgBuf.mbto, logBuf.lbname) == SAMESTRING) {
mPrintf("Can't send mail to yourself, silly!");
return FALSE;
}
}
}
}
strCpy(msgBuf.mbauth, logBuf.lbname); /* record author*/
if (uploading ||
getText("message", msgBuf.mbto, mode) == TRUE) {
if (!uploading) {
for (pc=msgBuf.mbtext, allUpper=TRUE; *pc && allUpper; pc++) {
if (toUpper(*pc) != *pc) allUpper = FALSE;
}
if (allUpper) fakeFullCase(msgBuf.mbtext, MAXTEXT);
}
if (toReturn=putMessage(uploading)) noteMessage(&lBuf, logNo);
}
return toReturn;
}
/************************************************************************/
/* mFormat() formats a string to modem and console */
/************************************************************************/
mFormat(string)
char *string;
#define MAXWORD 256 /* maximum length of a word */
{
char wordBuf[MAXWORD];
char mAbort();
int i;
for (i = 0; string[i] && (outFlag == OUTOK ||
outFlag == IMPERVIOUS ||
outFlag == OUTPARAGRAPH); ) {
i = getWord(wordBuf, string, i, MAXWORD);
putWord(wordBuf);
if (mAbort()) return;
}
}
/************************************************************************/
/* moveMessage() Moves a message for pullIt() */
/************************************************************************/
moveMessage(m)
int m;
{
label blah;
int i, roomTarg, ourRoom;
char prompt[55];
mPrintf("ove message\n ");
sPrintf(prompt, "where (C/R = '%s'): ", oldTarget);
getString(prompt, blah, 20, FALSE, ECHO);
if (!onLine()) return FALSE;
if (strLen(blah) == 0)
strCpy(blah, oldTarget);
if ((roomTarg = roomExists(blah)) == ERROR) {
mPrintf("'%s' does not exist.", blah);
return FALSE;
}
strCpy(oldTarget, roomTab[roomTarg].rtname);
pulledMLoc = roomBuf.msg[m].rbmsgLoc;
pulledMId = roomBuf.msg[m].rbmsgNo ;
for (i = m; i > 0; i--) {
roomBuf.msg[i].rbmsgLoc = roomBuf.msg[i - 1].rbmsgLoc;
roomBuf.msg[i].rbmsgNo = roomBuf.msg[i - 1].rbmsgNo ;
}
roomBuf.msg[0].rbmsgNo = 0l; /* mark new slot at end as free */
roomBuf.msg[0].rbmsgLoc = 0 ; /* mark new slot at end as free */
noteRoom();
putRoom(ourRoom = thisRoom);
getRoom(roomTarg);
note2Message(pulledMId, pulledMLoc);
putRoom(thisRoom);
noteRoom();
getRoom(ourRoom);
sPrintf(
msgBuf.mbtext,
"Following message from %s moved from %s> to %s> by %s",
(msgBuf.mbauth[0]) ? msgBuf.mbauth : "<anonymous>",
roomBuf.rbname,
oldTarget,
logBuf.lbname
);
aideMessage( /* noteDeletedMessage == */ TRUE);
return TRUE;
}
/************************************************************************/
/* mPeek() dumps a sector in message.buf. sysop debugging tool */
/************************************************************************/
mPeek()
{
#ifdef TEST_SYS
char visible();
char blup[50];
unsigned char peekBuf[SECTSIZE];
int col, row;
ulong r, s;
sPrintf(blup, " sector to dump (between 0 - %d): ", cfg.maxMSector);
s = getNumber(blup, 0, cfg.maxMSector-1);
r = s * SECTSIZE;
fseek(msgfl, r, 0);
fread(peekBuf, SECTSIZE, 1, msgfl);
crypte(peekBuf, SECTSIZE, 0);
for (row = 0; row < 2; row++) {
printf("\n ");
for (col = 0; col < 64; col++) {
printf("%c", visible(peekBuf[row*64 +col]));
}
}
#else
printf("Disabled\n");
#endif
}
/************************************************************************/
/* mspr() -- special function for this edition so we can be */
/* semi-intelligent in formatting. */
/************************************************************************/
#ifndef _C86_BIG
mspr(recip, start, length)
char **recip, *start;
unsigned length;
{
while (length-- != 0)
*(*recip)++ = *start++;
**recip = 0;
}
#else
static mspr(recip, start, length)
unsigned recip;
unsigned char *start;
unsigned length;
{
movmem(start, *starr[recip],length);
*starr[recip] += length;
**starr[recip]= 0;
}
#endif
/************************************************************************/
/* mPrintf() formats format+args to modem and console */
/************************************************************************/
#ifndef _C86_BIG
mPrintf(format, args)
unsigned char *format;
unsigned args;
{
int mspr();
char mAbort();
char string[MAXWORD], *s;
/* Here's all the fun, these 2 lines. Each C does it different */
s = string;
_fmtout(&mspr, &s, format, &args); /* C86 internal */
/* Ain't compatibility fun? */
mFormat(string);
}
#else
mPrintf(format, args)
unsigned char *format;
unsigned args;
{
unsigned char string[MAXWORD], *s;
s = string;
starr[j]=&s;
if(j>4){
exitValue = SYSOP_EXIT;
crashout("Big Model mPrintf crash!");
}
_fmtout(&mspr,j++,format,&args);
--j;
mFormat(string);
}
#endif
/************************************************************************/
/* mWCprintf() formats format+args to sendWCChar() */
/************************************************************************/
mWCprintf(format, args)
char *format;
unsigned args;
{
int dPree();
_fmtout(&dPree, 1, format, &args); /* C86 internal */
sendWCChar(0); /* Send NULL since it did before */
}
/************************************************************************/
/* noteLogMessage() slots message into log record */
/************************************************************************/
noteLogMessage(lBuf, logNo)
struct logBuffer *lBuf;
int logNo;
{
int i;
/* store into recipient's log record: */
/* slide message pointers down to make room for this one: */
for (i = 0; i < MAILSLOTS - 1; i++) {
lBuf->lbslot[i] = lBuf->lbslot[i + 1];
lBuf->lbId[ i] = lBuf->lbId[ i + 1];
}
/* slot this message in: */
lBuf->lbId[MAILSLOTS-1] = cfg.newest;
lBuf->lbslot[MAILSLOTS-1] = cfg.catSector;
putLog(lBuf, logNo);
}
/************************************************************************/
/* noteMessage() slots message into current room */
/************************************************************************/
noteMessage(lBuf, logNo)
struct logBuffer *lBuf;
int logNo;
{
struct logBuffer lBuf2;
int logRover;
logBuf.lbvisit[0] = ++cfg.newest;
if (thisRoom != MAILROOM) {
note2Message(cfg.newest, cfg.catSector);
/* write it to disk: */
putRoom(thisRoom);
noteRoom();
} else {
if (strCmpU(msgBuf.mbto, "Sysop") == SAMESTRING) {
if (!msgBuf.mbaddr[0]) {
getRoom(AIDEROOM);
/* enter in Aide> room -- 'sysop' is special */
note2Message(cfg.newest, cfg.catSector);
/* write it to disk: */
putRoom(AIDEROOM);
noteRoom();
getRoom(MAILROOM);
}
/* note in ourself if logged in: */
if (loggedIn) {
noteLogMessage(&logBuf, thisLog);
fillMailRoom();
}
} else if (strCmpU(msgBuf.mbto, "Citadel") == SAMESTRING &&
!msgBuf.mbaddr[0]) {
for (logRover = 0; logRover < cfg.MAXLOGTAB; logRover++) {
printf("Log %d\r", logRover); /* Notify sysop */
getLog(&lBuf2, logRover);
if (lBuf2.lbflags.L_INUSE) {
noteLogMessage(&lBuf2, logRover);
}
}
noteLogMessage(&logBuf, thisLog); /* note in ourself */
fillMailRoom(); /* update room also */
} else {
if (logNo != thisLog && !msgBuf.mbaddr[0]) {
noteLogMessage(lBuf, logNo); /* note in recipient*/
}
if (loggedIn) {
noteLogMessage(&logBuf, thisLog); /* note in ourself */
fillMailRoom(); /* update room also */
}
}
}
msgBuf.mbaddr[0] = 0;
msgBuf.mbto[0] = 0;
/* make message official: */
cfg.catSector = mFile1.thisSector;
cfg.catChar = mFile1.thisChar;
setUp(FALSE);
}
/************************************************************************/
/* note2Message() makes slot in current room... called by noteMess */
/************************************************************************/
note2Message(id, loc)
ulong id;
unsigned loc;
{
int i;
/* store into current room: */
/* slide message pointers down to make room for this one: */
for (i = 0; i < MSGSPERRM - 1; i++) {
roomBuf.msg[i].rbmsgLoc = roomBuf.msg[i+1].rbmsgLoc;
roomBuf.msg[i].rbmsgNo = roomBuf.msg[i+1].rbmsgNo ;
}
/* slot this message in: */
roomBuf.msg[MSGSPERRM-1].rbmsgNo = id ;
roomBuf.msg[MSGSPERRM-1].rbmsgLoc = loc;
}
/************************************************************************/
/* printMessage() prints indicated message on modem & console */
/************************************************************************/
printMessage(loc, id, name_Auth)
char *name_Auth; /* Author buffer if thisRoom == mailRoom */
unsigned loc; /* sector in message.buf */
ulong id; /* unique-for-some-time ID# */
{
char dGetWord();
char c, moreFollows;
ulong here;
long val, atoi();
int strip;
startAt(msgfl, &mFile1, loc, 0);
do {
getMessage();
sscanf(msgBuf.mbId, "%ld", &here);
} while (here != id && mFile1.thisSector == loc);
if (here != id && !usingWCprotocol) {
mPrintf("?can't find message! Looking for %lu in sector %u!\n ",
id, loc);
if (debug)
printf(" loc=%u, id=%lu, mbIds=%s, here=%lu\n",
loc, id, msgBuf.mbId, here
);
return;
}
if (!usingWCprotocol) {
doCR();
if (msgBuf.mbdate[ 0]) mPrintf(" %s ", msgBuf.mbdate);
if (msgBuf.mbtime[ 0] && sendTime) mPrintf("%s ", msgBuf.mbtime);
if (msgBuf.mbauth[ 0]) {
mPrintf( "from %s", msgBuf.mbauth );
if (thisRoom == MAILROOM)
strCpy(name_Auth, msgBuf.mbauth);
}
if (msgBuf.mboname[0]) mPrintf( " @%s", msgBuf.mboname);
if (strCmpU(msgBuf.mbroom, roomBuf.rbname) != SAMESTRING) {
mPrintf(" in %s>", msgBuf.mbroom );
}
if (msgBuf.mbto[ 0]) mPrintf( " to %s", msgBuf.mbto );
if (msgBuf.mbaddr[ 0]) mPrintf( " (on %s)", msgBuf.mbaddr );
doCR();
while (1) {
moreFollows = dGetWord(msgBuf.mbtext, 150);
/* strip control Ls out of the output */
for (strip = 0; msgBuf.mbtext[strip] != 0; strip++)
if (msgBuf.mbtext[strip] == 0x0c)
msgBuf.mbtext[strip] = ' ';
putWord(msgBuf.mbtext);
if (!(moreFollows && !mAbort())) {
if (outFlag == OUTNEXT) /* If <N>ext, extra line */
doCR();
break;
}
}
doCR();
}
else {
/* networking dump of message: */
/* fill in local node in origin fields if local message: */
if (!msgBuf.mborig[ 0])
strCpy(msgBuf.mborig, cfg.nodeId + cfg.codeBuf );
if (!msgBuf.mboname[0])
strCpy(msgBuf.mboname, cfg.nodeName + cfg.codeBuf);
/* Convert # to 8-bit Citadel style for compatibility */
if (!msgBuf.mbsrcId[0]) {
val = atoi(msgBuf.mbId);
sPrintf(msgBuf.mbsrcId, "%ld %ld",
val & 0xFFFF0000l,val & 0xFFFFl);
}
/* send header fields out: */
if (msgBuf.mbauth[ 0]) mWCprintf("A%s", msgBuf.mbauth );
if (msgBuf.mbdate[ 0]) mWCprintf("D%s", msgBuf.mbdate );
if (msgBuf.mbtime[ 0]) mWCprintf("C%s", msgBuf.mbtime );
if (msgBuf.mboname[0]) mWCprintf("N%s", msgBuf.mboname);
if (msgBuf.mborig[ 0]) mWCprintf("O%s", msgBuf.mborig );
if (msgBuf.mbroom[ 0]) mWCprintf("R%s", msgBuf.mbroom );
if (msgBuf.mbsrcId[0]) mWCprintf("S%s", msgBuf.mbsrcId);
if (msgBuf.mbto[ 0]) mWCprintf("T%s", msgBuf.mbto );
/* send message text proper: */
sendWCChar('M');
do {
c = getMsgChar();
if (c=='\n') c='\r';
if (!sendWCChar(c)) break;
} while (c);
}
msgBuf.mbaddr[0] = 0;
}
/************************************************************************/
/* pullIt() is a sysop special to remove a message from a room */
/************************************************************************/
pullIt(m)
int m;
{
char finished;
label blah;
char answer;
/* confirm that we're removing the right one: */
outFlag = OUTOK;
printMessage(roomBuf.msg[m].rbmsgLoc, roomBuf.msg[m].rbmsgNo, blah);
for (finished = FALSE; !finished;) {
do {
outFlag = IMPERVIOUS;
mPrintf("\n <D>elete <M>ove <A>bort? (D/M/A) ");
answer = toUpper(iChar());
if (answer == 'A' ||
answer == 'D' ||
answer == 'M')
break;
} while (onLine());
outFlag = OUTOK;
if (answer == 'A' || !onLine()) return FALSE;
if (answer == 'D') finished = deleteMessage(m);
else if (answer == 'M') finished = moveMessage(m);
}
return TRUE;
}
/************************************************************************/
/* putLong() puts a long integer to file fd */
/************************************************************************/
putLong(fd, nm)
FILE *fd;
ulong nm;
{
unsigned char c;
c = (unsigned char) ((nm & 0xFF000000) >> 24);
if (fputc(c, fd) == EOF) {
exitValue = CRASH_EXIT;
crashout("putLong error!");
}
c = (unsigned char) ((nm & 0x00FF0000) >> 16);
if (fputc(c, fd) == EOF) {
exitValue = CRASH_EXIT;
crashout("putLong error!");
}
c = (unsigned char) ((nm & 0x0000FF00) >> 8);
if (fputc(c, fd) == EOF) {
exitValue = CRASH_EXIT;
crashout("putLong error!");
}
c = (unsigned char) (nm & 0x000000FF);
if (fputc(c, fd) == EOF) {
exitValue = CRASH_EXIT;
crashout("putLong error!");
}
}
/************************************************************************/
/* putMessage() stores a message to disk */
/* Always called before noteMessage() -- newest not ++ed yet. */
/* Returns: TRUE on successful save, else FALSE */
/************************************************************************/
char putMessage(uploading)
char uploading; /* true to get text via WC modem input, not RAM */
{
char *s, allOk, *month, *ml;
label fn, ourCode, theirCode;
int putWCChar();
int year, day, h, m, netPlace;
FILE *fopen(), *fd;
startAt(msgfl, &mFile1, cfg.catSector, cfg.catChar);
/* tell putMsgChar where to write */
if (cfg.mirror)
startAt(msgfl2, &mFile2, cfg.catSector, cfg.catChar);
putMsgChar(0xFF); /* start-of-message */
/* write message ID */
dPrintf("%lu", cfg.newest + 1);
putMsgChar(0);
/* write date: */
getdate(&year, &month, &day, &h, &m);
dPrintf("D%d%s%02d", year, month, day);
putMsgChar(0);
/* write time: */
if (h >= 12)
ml = "pm";
else
ml = "am";
if (h >= 13)
h -= 12;
if (h == 0)
h = 12;
dPrintf("C%d:%02d %s", h, m, ml);
putMsgChar(0);
/* write room name out: */
dPrintf("R%s", roomBuf.rbname);
putMsgChar(0);
if (loggedIn || strCmpU(msgBuf.mbauth, "Citadel") == SAMESTRING) {
/* write author's name out: */
dPrintf("A%s", msgBuf.mbauth);
putMsgChar(0); /* null to end string */
}
if (msgBuf.mbto[0]) { /* private message -- write addressee */
dPrintf("T%s", msgBuf.mbto);
putMsgChar(0);
}
if (msgBuf.mbaddr[0]) { /* net message routing -- put to temp */
netPlace = searchNameNet(msgBuf.mbaddr);
getNet(netPlace);
sPrintf(fn, "a:%d.ml", thisNet);
fn[0] += cfg.netDisk;
if ((fd = fopen(fn, "ab")) == NULL) {
exitValue = CRASH_EXIT;
crashout("putMessage -- couldn't open mail router!");
}
putLong(fd, cfg.newest + 1);
fputc(((cfg.catSector & 0xff00) >> 8), fd);
fputc(((cfg.catSector & 0xff)), fd);
fclose(fd);
getArea(cfg.codeBuf + cfg.nodeId, ourCode );
getArea(netBuf.netId , theirCode);
if (strCmpU(theirCode, ourCode) != SAMESTRING) {
if (logBuf.credit == 0) {
exitValue = CRASH_EXIT;
crashout("Someone obtained illegal l-d networking privs!");
}
logBuf.credit--;
storeLog();
}
netBuf.nbflags.normal_mail = TRUE;
putNet(netPlace);
dPrintf("Q%s", netBuf.netName);
putMsgChar(0);
}
/* write message text by hand because it would overrun dPrintf buffer: */
putMsgChar('M'); /* M-for-message. */
if (!uploading) {
for (s = msgBuf.mbtext; *s; s++) putMsgChar(*s);
allOk = TRUE;
} else {
outFlag = FALSE; /* setup for putWCChar() */
allOk = readFile(putWCChar);
}
if (allOk) {
putMsgChar(0); /* null to end text */
flushMsgBuf();
} else {
flushMsgBuf(); /* so message count is ok */
/* erase start-of-message indicator: */
startAt(msgfl, &mFile1, cfg.catSector, cfg.catChar);
if (cfg.mirror)
startAt(msgfl2, &mFile2, cfg.catSector, cfg.catChar);
putMsgChar(0); /* overwrite 0xFF byte */
}
return allOk;
}
/************************************************************************/
/* putMsgChar() writes successive message chars to disk */
/* Globals: thisChar= thisSector= */
/* Returns: ERROR if problems else TRUE */
/************************************************************************/
int putMsgChar(c)
unsigned char c;
{
int toReturn;
int count1, count2;
long temp;
toReturn = TRUE;
count1 = doActualWrite(msgfl, &mFile1, c);
if (cfg.mirror) {
count2 = doActualWrite(msgfl2, &mFile2, c);
if (count1 != count2) printf("Mirror msg count discrepancy!");
}
if (count1)
logBuf.lbvisit[(MAXVISIT-1)] = ++cfg.oldest;
return toReturn;
}
/************************************************************************/
/* putNetMessage() stores a message to disk */
/* Always called before noteMessage() -- newestLo not ++ed yet. */
/* Returns: TRUE on successful save, else FALSE. */
/************************************************************************/
putNetMessage()
{
char *s, allOk;
startAt(msgfl, &mFile1, cfg.catSector, cfg.catChar);
/* tell putMsgChar where to write */
if (cfg.mirror)
startAt(msgfl2, &mFile2, cfg.catSector, cfg.catChar);
putMsgChar(0xFF); /* start-of-message */
/* write message ID */
dPrintf("%lu", cfg.newest + 1);
putMsgChar(0);
/* write date: */
dPrintf("D%s", tempMess.mbdate);
putMsgChar(0);
/* write room name out: */
dPrintf("R%s", roomBuf.rbname);
putMsgChar(0);
/* write source node name out: */
dPrintf("N%s", tempMess.mboname);
putMsgChar(0);
/* write source node id out: */
dPrintf("O%s", tempMess.mborig);
putMsgChar(0);
/* write source id out: */
dPrintf("S%s", tempMess.mbsrcId);
putMsgChar(0);
if (tempMess.mbauth[0]) {
/* write author's name out: */
dPrintf("A%s", tempMess.mbauth);
putMsgChar(0); /* null to end string */
}
if (tempMess.mbto[0]) { /* private message -- write addressee */
dPrintf("T%s", tempMess.mbto);
putMsgChar(0);
}
if (tempMess.mbtime[0]) {
dPrintf("C%s", tempMess.mbtime);
putMsgChar(0);
}
/* write message text by hand because it would overrun dPrintf buffer: */
putMsgChar('M'); /* M-for-message. */
for (s=tempMess.mbtext; *s; s++) putMsgChar(*s);
putMsgChar(0); /* null to end text */
flushMsgBuf();
}
/************************************************************************/
/* putWord() writes one word to modem & console */
/************************************************************************/
putWord(st)
char *st;
{
char *s;
int newColumn;
for (newColumn = crtColumn, s = st; *s; s++) {
if (*s != TAB) ++newColumn;
else while (++newColumn % 8);
}
if (newColumn > termWidth) doCR();
for (; *st; st++) {
if (*st != TAB) ++crtColumn;
else while (++crtColumn % 8);
/* worry about words longer than a line: */
if (crtColumn > termWidth) doCR();
if (prevChar!=NEWLINE || (*st > ' ')) oChar(*st);
else {
/* end of paragraph: */
if (outFlag == OUTPARAGRAPH) {
outFlag = OUTOK;
}
doCR();
oChar(*st);
}
}
}
/************************************************************************/
/* showMessages() is routine to print roomful of msgs */
/************************************************************************/
showMessages(whichMess, revOrder)
char whichMess, revOrder;
{
char name_Auth[NAMESIZE];
int i;
int start, finish, increment;
ulong lowLim, highLim, msgNo;
char pulled;
setUp(FALSE);
if (thisRoom == MAILROOM && !loggedIn) {
tutorial("POLICY.HLP");
return ;
}
if (!expert && !usingWCprotocol)
mPrintf("\n <J>ump <N>ext <P>ause <S>top");
if (whichIO != CONSOLE && thisRoom == MAILROOM) echo = CALLER;
/* Allow for reverse retrieval: */
if (!revOrder) {
start = 0;
finish = MSGSPERRM;
increment = 1;
} else {
start = (MSGSPERRM -1);
finish = -1;
increment = -1;
}
switch (whichMess) {
case NEWoNLY:
lowLim = logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK]+1;
highLim = cfg.newest;
if (!revOrder && !usingWCprotocol && thisRoom != MAILROOM && oldToo) {
for (i = MSGSPERRM - 1; i != -1; i--)
if (lowLim > roomBuf.msg[i].rbmsgNo &&
roomBuf.msg[i].rbmsgNo >= cfg.oldest)
break;
if (i != -1)
printMessage(roomBuf.msg[i].rbmsgLoc, roomBuf.msg[i].rbmsgNo,
name_Auth);
}
break;
case OLDaNDnEW:
lowLim = cfg.oldest;
highLim = cfg.newest;
break;
case OLDoNLY:
lowLim = cfg.oldest;
highLim = logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK];
break;
}
/* stuff may have scrolled off system unseen, so: */
if (cfg.oldest > lowLim) {
lowLim = cfg.oldest;
}
for (i = start; i != finish && onLine(); i += increment) {
if (outFlag != OUTOK) {
if (outFlag == OUTNEXT || outFlag == OUTPARAGRAPH)
outFlag = OUTOK;
else if (outFlag == OUTSKIP) {
echo = BOTH;
return;
}
}
msgNo = roomBuf.msg[i].rbmsgNo;
if (
msgNo >= lowLim
&&
highLim >= msgNo
) {
printMessage(roomBuf.msg[i].rbmsgLoc, msgNo, name_Auth);
/* Pull current message from room if flag set */
if (pullMessage) {
pullMessage = FALSE;
pulled = pullIt(i);
outFlag = OUTOK;
if (revOrder && pulled) i++;
}
else
pulled = FALSE;
if (
!usingWCprotocol
&&
!pulled
&&
strCmpU(name_Auth, logBuf.lbname) != SAMESTRING
&&
thisRoom == MAILROOM
&&
whichMess == NEWoNLY
&&
msgBuf.mborig[0] == 0 /* i.e. is local mail */
&&
getYesNo("respond")
) {
if (makeMessage( /* uploading== */ FALSE, name_Auth, 0,FALSE))
i--;
if (whichIO != CONSOLE && thisRoom == MAILROOM)
echo = CALLER; /* Restore privacy zapped by make... */
outFlag = OUTOK;
}
}
}
echo = BOTH;
}
/************************************************************************/
/* startAt() sets location to begin reading message from */
/************************************************************************/
startAt(whichmsg, mFile, sect, byt)
unsigned sect;
int byt;
FILE *whichmsg;
struct mBuf *mFile;
{
long temp;
GMCCache = '\0'; /* cache to unGetMsgChar() into */
if (sect >= cfg.maxMSector) {
printf("?startAt s=%u,b=%d", sect, byt);
exitValue = CRASH_EXIT;
crashout("?startAt crash");
}
mFile->thisChar = byt;
mFile->thisSector = sect;
temp = sect;
temp *= SECTSIZE;
fseek(whichmsg, temp, 0);
if (fread(mFile->sectBuf, SECTSIZE, 1, whichmsg) != 1) {
exitValue = CRASH_EXIT;
crashout("?startAt read fail");
}
crypte(mFile->sectBuf, SECTSIZE, 0);
}
/************************************************************************/
/* unGetMsgChar() returns (at most one) char to getMsgChar() */
/************************************************************************/
unGetMsgChar(c)
unsigned char c;
{
GMCCache = c;
}
/************************************************************************/
/* exportSector() returns current sector to write to */
/************************************************************************/
unsigned exportSector()
{
return mFile1.thisSector;
}